import * as THREE from '../../../../modules/three/three.module.js'
import {flatten} from "../util/StaticMethods.js";
import {WorldConfig} from "../CommonConsts.js";

const size = 0.12
const quat = new THREE.Quaternion().setFromUnitVectors(new THREE.Vector3(1, 1, 1).normalize(), new THREE.Vector3(0, -1, 0))
const mat = new THREE.Matrix4().makeRotationFromQuaternion(quat)
mat.setPosition(0, size, 0)
const origin = new THREE.Vector3(0, 0, 0)
const unitY = new THREE.Vector3(0, 1, 0)
const unitNegY = new THREE.Vector3(0, -1, 0)
const showBottomPlane = true
const lineAbove = 0.5
const tmp = new THREE.Vector3()
const tmp2 = new THREE.Vector3()
const _direction = new THREE.Vector3()
const mid = new THREE.Vector3()
const horizontalOffset = true
const showBaseLine = false

export default class RoutePointIndicator extends THREE.Mesh {
  /**
   * @type {RoutePointVO}
   */
  vo
  /**
   * @type {RoutePointVO|null}
   */
  previousVO
  bottomMesh
  _line
  _line4Drone
  _drone

  constructor(vo, scene) {
    super()
    // const geometry = new THREE.OctahedronGeometry(size)
    // mat.makeTranslation(0, size, 0)
    // geometry.applyMatrix4(mat)
    const geometry = new THREE.TetrahedronGeometry(size)
    geometry.applyMatrix4(mat)
    const mtl = new THREE.MeshBasicMaterial({
      color: '#0e441f',
      wireframe: true,
      transparent: true,
      opacity: 0.5,
      // colorWrite: false,
    })
    this.geometry = geometry
    this.material = mtl
    this.renderOrder = WorldConfig.order_route_point
    this._createBottomPlane()
    this.vo = vo
    this._createDroneIndicator(scene)
    this.syncToVO()
  }

  markAsStart() {
    this.material.color.setStyle('#ff6000')
    this._drone.material.color.setStyle('#ff6000')
  }
  markAsEnd() {
    this.material.color.setStyle('#0f0')
    this._drone.material.color.setStyle('#0f0')
  }
  markAsMiddle() {
    this.material.color.setStyle('#0e441f')
    this._drone.material.color.setStyle('#0e441f')
  }

  _createDroneIndicator(scene) {
    const geometry = new THREE.TetrahedronGeometry(size)
    geometry.applyMatrix4(mat)
    const mtl = new THREE.MeshBasicMaterial({color: '#c71531', wireframe: true})
    const mesh = new THREE.Mesh(geometry, mtl)
    scene.add(mesh)

    const posAttr = new THREE.BufferAttribute(new Float32Array([0, 0, 0,  0, -1, 0]), 3)
    const lineGeo = new THREE.BufferGeometry();
    lineGeo.setAttribute('position', posAttr);
    lineGeo.setIndex([0, 1]);
    const lineSegments = new THREE.LineSegments(lineGeo, new THREE.LineBasicMaterial({ color: '#522f06', toneMapped: false }));
    mesh.add(lineSegments)
    this._drone = mesh
    // this._syncDroneToVO()
  }

  _syncDroneToVO() {
    const {dronePosition, droneHeading} = this.vo.getDronePosAndHeading()
    this._drone.position.copy(dronePosition)
    this._drone.quaternion.setFromUnitVectors(unitNegY, droneHeading)
    this._drone.children[0].scale.y = this.vo.getOffsetSize()
  }

  _createBottomPlane() {
    const radius = 0.5
    const height = 1

    const pts = [origin];
    const faceIndices = [];
    const lineIndices = [];
    const segment = 32;
    const angle = (Math.PI * 2) / segment;
    for (let i = 0; i < segment; i++) {
      const a = angle * i;
      const x = radius * Math.sin(a);
      const z = radius * Math.cos(a);
      const pt = new THREE.Vector3(x, 0, z);
      pts.push(pt);
      if (i === segment - 1) {
        lineIndices.push(1, segment);
        faceIndices.push(0, segment, 1);
      } else {
        lineIndices.push(i + 1, i + 2);
        faceIndices.push(0, i + 1, i + 2);
      }
    }

    pts.push(new THREE.Vector3(0, height, 0));
    lineIndices.push(0, segment + 1);
    const geometry = new THREE.BufferGeometry()
    geometry.setIndex(faceIndices)
    const posAttr = new THREE.BufferAttribute(flatten(pts), 3)
    geometry.setAttribute('position', posAttr)
    const mtl = new THREE.MeshBasicMaterial({color: '#009d32', opacity: 0.4, transparent: true})
    const bottomMesh = new THREE.Mesh(geometry, mtl)
    const lineGeo = new THREE.BufferGeometry();
    lineGeo.setIndex(lineIndices);
    lineGeo.setAttribute('position', posAttr);
    const lineSegments = new THREE.LineSegments(
      lineGeo,
      new THREE.LineBasicMaterial({ color: '#0e4117', toneMapped: false }),
    );
    bottomMesh.add(lineSegments)
    this.add(bottomMesh)
    this.bottomMesh = bottomMesh
    this.bottomMesh.visible = showBottomPlane
  }

  updateRadius(radius) {
    const scale = radius / 0.5
    this.bottomMesh.scale.set(scale, 1, scale)
    this.vo.radius = radius
  }
  createLine(scene, preVO) {
    const {position, normal} = preVO
    if (showBaseLine) {
      tmp.copy(normal).multiplyScalar(lineAbove).add(position)
      tmp2.copy(this.vo.normal).multiplyScalar(lineAbove).add(this.position)
      const posAttr = new THREE.BufferAttribute(new Float32Array([tmp.x, tmp.y, tmp.z, tmp2.x, tmp2.y, tmp2.z]), 3)
      const lineGeo = new THREE.BufferGeometry();
      lineGeo.setAttribute('position', posAttr);
      lineGeo.setIndex([0, 1]);
      const lineSegments = new THREE.LineSegments(lineGeo, new THREE.LineBasicMaterial({ color: '#1968c2', toneMapped: false }));
      this._line = lineSegments
      scene.add(lineSegments)
    }

    if (!this._drone) {
      return
    }
    const posAttr2 = new THREE.BufferAttribute(new Float32Array([0,-0.5,0, 0,0.5,0]), 3)
    const lineGeo2 = new THREE.BufferGeometry();
    lineGeo2.setAttribute('position', posAttr2);
    lineGeo2.setIndex([0, 1]);
    const lineColor = this.vo.endSpraying() ? '#000' : '#229848'
    const lineSegments2 = new THREE.LineSegments(lineGeo2, new THREE.LineBasicMaterial({ color: lineColor, toneMapped: false }));
    this._line4Drone = lineSegments2
    scene.add(lineSegments2)
    this.updateLine4Drone(preVO)
  }

  updateLine4Drone(previousVO) {
    let preVO = previousVO
    if (previousVO) {
      this.previousVO = previousVO
    } else {
      preVO = this.previousVO
    }
    if (!preVO) {
      return
    }
    const {dronePosition} = preVO.getDronePosAndHeading()
    const span = dronePosition.distanceTo(this._drone.position)
    _direction.copy(this._drone.position).sub(dronePosition).normalize()
    this._line4Drone.scale.y = span
    this._line4Drone.position.copy(dronePosition).lerp(this._drone.position, 0.5)
    this._line4Drone.quaternion.setFromUnitVectors(unitY, _direction)
  }
  initDroneLineTip(tipPos) {
    if (!this.previousVO) {
      return 0
    }
    const {dronePosition} = this.previousVO.getDronePosAndHeading()
    tipPos.copy(dronePosition).lerp(this._drone.position, 0.5)
    return dronePosition.distanceTo(this._drone.position)
  }
  updateLine(preVO) {
    if (this._line4Drone) {
      this.updateLine4Drone(preVO)
    }
    if (!this._line) {
      return
    }
    const posAttr = this._line.geometry.getAttribute('position')
    tmp.copy(this.vo.normal).multiplyScalar(lineAbove).add(this.position)
    const {x, y, z} = tmp
    posAttr.setXYZ(1, x, y, z)
    if (preVO) {
      const {position, normal} = preVO
      tmp.copy(normal).multiplyScalar(lineAbove).add(position)
      posAttr.setXYZ(0, tmp.x, tmp.y, tmp.z)
    }
    posAttr.needsUpdate = true
  }
  restoreLine(scene, preVO) {
    if (!this._line4Drone) {
      this.createLine(scene, preVO)
    } else {
      if (this._line) {
        scene.add(this._line)
      }
      scene.add(this._line4Drone)
      this.updateLine(preVO)
    }
  }
  /**
   * 航点颜色，半径，偏移类型从 所属的航线继承
   * @param {RouteVO} routeVO
   */
  inheritRouteProperties(routeVO) {
    this.changeColor(routeVO.getPaintColor())
    this.updateRadius(routeVO.getPointRadius())
    this.vo.offsetType = routeVO.getOffsetType()
    this._syncDroneToVO()
  }
  changeColor(cssColor) {
    this.bottomMesh.material.color.setStyle(cssColor)
    if (this._line4Drone) {
      this._line4Drone.material.color.setStyle(cssColor)
    }
  }
  toggleSelected(selected) {
    // this.material.opacity = selected ? 0.0 : 0.4;
    this.material.wireframe = !selected
    this._drone.material.wireframe = !selected
  }
  updateVO() {
    this.vo.position.copy(this.position)
    this.vo.normal.copy(unitY).applyQuaternion(this.quaternion)
  }
  syncToVO() {
    this.position.copy(this.vo.position)
    this.quaternion.setFromUnitVectors(unitY, this.vo.normal)
    if (this._drone) {
      this._syncDroneToVO()
    }
  }

  disposeLine() {
    if (this._line) {
      this._line.removeFromParent()
      // this._line = null
    }
    if (this._drone) {
      this._drone.removeFromParent()
    }
    if (this._line4Drone) {
      this._line4Drone.removeFromParent()
    }
  }
  unDisposeLine(scene) {
    if (this._line) {
      scene.add(this._line)
    }
    if (this._drone) {
      scene.add(this._drone)
    }
    if (this._line4Drone) {
      scene.add(this._line4Drone)
    }
  }
}
